/*
 * libExtended2.h
 *
 *  Created on: 16/04/2012
 *      Author: utnso
 */

#ifndef LIBEXTENDED2_H_
#define LIBEXTENDED2_H_

//INCLUDES
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <stdbool.h>

#include "libDisco.h"
#include "libPath.h"
#include "libMat.h"

//CONSTANTES
//#define BLOCK_SIZE 1024

//TIPOS
typedef struct t_bootRecord{

} /*__attribute__((packed))*/ t_bootRecord;

typedef struct superBlock_t{
	uint32_t inodesCount; //numero total de inodos en el file system.
	uint32_t blocksCount; //numero total de bloques en el file system.
	uint32_t reservedBlocksCount; //numero de bloques reservados para uso del super user.
	uint32_t freeBlocksCount; //numero de bloques libres, incluso los reservados, de todos los grupos de bloques. ¿solo los libres de los reservados o los reservados completos?
	uint32_t freeInodesCount; //numero de inodos libres de todos los grupos de bloques.
	uint32_t firstDataBlock; //numero del bloque que contiene el super bloque.
	uint32_t blockSize; //tamanio de los bloques (siempre mayor a 0) (tamanioBloque = 1024 << blockSize;).
	int32_t fragmentSize; //tamanio de los fragmentos (mayor o menor a 0) (if(fragmentSize > 0) tamanioFragmento = 1024 << fragmentSize; else tamanioFragmento = 1024 >> -fragmentSize;).
	uint32_t blocksPerGroup; //numero de bloques por grupo de bloques.
	uint32_t fragmentsPerGroup; //numero de fragmentos por grupo de bloques.
	uint32_t inodesPerGroup; //numero de inodos por grupo de bloques.
	uint32_t mTime; //tiempo de la ultima vez que el file system fue montado.
	uint32_t wTime; //tiempo de la ultima vez que el file system fue accedido para escritura.
	uint16_t mntCount; //cantidad de veces que el file system fue montado desde la ultima vez que fue verificado completamente.
	uint16_t mntMaxCount; //maxima cantidad de veces que el file system puede ser montado sin ser verificado completamente.
	uint16_t magic; //numero que define el file system como Ext2, normalmente seteado a 0xEF53.
	uint16_t state; //numero que indica el estado del file system, puede valer EXT2_ERROR_FS si el file system esta montado o fue desmontado incorrectamente, o EXT2_VALID_FS si no se encuentra montado.
	uint16_t errors; //indica lo que debe hacer el driver del file system en caso de error.
	uint16_t minorRevLevel;
	uint32_t lastCheck; //tiempo del ultimo chequeo.
	uint32_t checkInterval; //maxima cantidad de intervalos de tiempo entre chequeos.
	uint32_t creatorOS; //numero que identifica el sistema operativo con el que fue montado el file system.
	uint32_t revLevel;
	uint16_t defResUID;
	uint16_t defResGID;
	//---------- VERSION DINAMICA----------//
	uint32_t firstInode; //numero que identifica el primer inodo accesible para archivos estandar, en la version no dinamica ese inodo era siempre el 11.
	uint16_t inodeSize; //tamanio del inodo, en la version no dinamica siempre eran de 128 bytes.
	uint16_t superBlockGroup; //numero del grupo de bloques que contiene el super bloque.
	uint32_t featureCompat;
	uint32_t featureIncompat;
	uint32_t featureROCompat;
	uint8_t UUID[16];
	char volumeName[16];
	char lastMountedDirectory[64];
	uint32_t algoBitmap;
	//----------PERFORMANCE HINTS----------//
	uint8_t preallocBlocks;
	uint8_t preallocDirBlocks;
	uint16_t alignment;
	//----------JOURNALING SUPPORT----------//
	uint8_t journalUUID[16];
	uint32_t journalINum;
	uint32_t journalDev;
	uint32_t lastOrphan;
	//----------UNUSED----------//
	char padding[788];
} /*__attribute__((packed))*/ superBlock_t;

typedef struct staticSuperBlock_t{
	uint8_t inicializado;
	uint32_t inodesCount; //numero total de inodos en el file system.
	uint32_t blocksCount; //numero total de bloques en el file system.
	uint32_t reservedBlocksCount; //numero de bloques reservados para uso del super user.
	//uint32_t freeBlocksCount; //numero de bloques libres, incluso los reservados, de todos los grupos de bloques. ¿solo los libres de los reservados o los reservados completos?
	//uint32_t freeInodesCount; //numero de inodos libres de todos los grupos de bloques.
	uint32_t firstDataBlock; //numero del bloque que contiene el super bloque.
	uint32_t blockSize; //tamanio de los bloques (siempre mayor a 0) (tamanioBloque = 1024 << blockSize;).
	int32_t fragmentSize; //tamanio de los fragmentos (mayor o menor a 0) (if(fragmentSize > 0) tamanioFragmento = 1024 << fragmentSize; else tamanioFragmento = 1024 >> -fragmentSize;).
	uint32_t blocksPerGroup; //numero de bloques por grupo de bloques.
	uint32_t fragmentsPerGroup; //numero de fragmentos por grupo de bloques.
	uint32_t inodesPerGroup; //numero de inodos por grupo de bloques.
	//uint32_t mTime; //tiempo de la ultima vez que el file system fue montado.
	//uint32_t wTime; //tiempo de la ultima vez que el file system fue accedido para escritura.
	//uint16_t mntCount; //cantidad de veces que el file system fue montado desde la ultima vez que fue verificado completamente.
	//uint16_t mntMaxCount; //maxima cantidad de veces que el file system puede ser montado sin ser verificado completamente.
	//uint16_t magic; //numero que define el file system como Ext2, normalmente seteado a 0xEF53.
	//uint16_t state; //numero que indica el estado del file system, puede valer EXT2_ERROR_FS si el file system esta montado o fue desmontado incorrectamente, o EXT2_VALID_FS si no se encuentra montado.
	//uint16_t errors; //indica lo que debe hacer el driver del file system en caso de error.
	//uint16_t minorRevLevel;
	//uint32_t lastCheck; //tiempo del ultimo chequeo.
	//uint32_t checkInterval; //maxima cantidad de intervalos de tiempo entre chequeos.
	//uint32_t creatorOS; //numero que identifica el sistema operativo con el que fue montado el file system.
	//uint32_t revLevel;
	//uint16_t defResUID;
	//uint16_t defResGID;
	//---------- VERSION DINAMICA----------//
	uint32_t firstInode; //numero que identifica el primer inodo accesible para archivos estandar, en la version no dinamica ese inodo era siempre el 11.
	uint16_t inodeSize; //tamanio del inodo, en la version no dinamica siempre eran de 128 bytes.
	uint16_t superBlockGroup; //numero del grupo de bloques que contiene el super bloque.
	//uint32_t featureCompat;
	//uint32_t featureIncompat;
	//uint32_t featureROCompat;
	//uint8_t UUID[16];
	//char volumeName[16];
	//char lastMountedDirectory[64];
	//uint32_t algoBitmap;
	//----------PERFORMANCE HINTS----------//
	//uint8_t preallocBlocks;
	//uint8_t preallocDirBlocks;
	//uint16_t alignment;
	//----------JOURNALING SUPPORT----------//
	//uint8_t journalUUID[16];
	//uint32_t journalINum;
	//uint32_t journalDev;
	//uint32_t lastOrphan;
	//----------UNUSED----------//
	//char padding[788];
} /*__attribute__((packed))*/ staticSuperBlock_t;

typedef struct groupDescriptor_t{
	uint32_t blockBitmap; //numero que identifica el primer bloque del bitmap de bloques del grupo.
	uint32_t inodeBitmap; //numero que identifica el primer bloque del bitmap de inodes del grupo.
	uint32_t inodeTable; //numero que identifica el primer bloque de la tabla de inodos del grupo.
	uint16_t freeBlocksCount; //cantidad de bloques libres en el grupo.
	uint16_t freeInodesCount; //cantidad de inodos libres en el grupo.
	uint16_t freeDirsCount; //cantidad de inodos dedicados a directorios en el gruop.
	uint16_t pad;
	uint8_t reserved[12];
} __attribute__((packed)) groupDescriptor_t;

typedef struct staticGroupDescriptor_t{
	uint32_t blockBitmap; //numero que identifica el primer bloque del bitmap de bloques del grupo.
	uint32_t inodeBitmap; //numero que identifica el primer bloque del bitmap de inodes del grupo.
	uint32_t inodeTable; //numero que identifica el primer bloque de la tabla de inodos del grupo.
} /*__attribute__((packed))*/ staticGroupDescriptor_t;

typedef struct inodeStructure_t{
	uint16_t mode; //formato del archivo y derechos de acceso.
	uint16_t UID; //user id asociado con el archivo.
	uint32_t size; //tamanio del archivo en bytes.
	uint32_t aTime; //cantidad de segundos desde el 1 de Enero de 1970 hasta la ultima vez que el archivo fue accedido.
	uint32_t cTime;//cantidad de segundos desde el 1 de Enero de 1970 hasta que el archivo fue creado.
	uint32_t mTime;//cantidad de segundos desde el 1 de Enero de 1970 hasta la ultima vez que el archivo fue modificado.
	uint32_t dTime;//cantidad de segundos desde el 1 de Enero de 1970 hasta que el archivo fue eliminado. Si el archivo no fue eliminado es 0.
	uint16_t GID; //id del grupo que tiene acceso a este archivo.
	uint16_t linksCount; //cuantas veces este inodo es referenciado.
	uint32_t blocks; //cantidad de bloques de datos (siempre 512 bytes) asociados con este archivo, tanto en uso como reservados para el aumento de tamanio del archivo.
	uint32_t flags;
	uint32_t osd1;
	uint32_t* block[15];
	uint32_t generation;
	uint32_t fileACL;
	uint32_t dirACL;
	uint32_t fAddr;
	uint8_t* osd2[12];
} __attribute__((packed)) inodeStructure_t;

typedef struct byteBitmap_t{
	bool byte0 :1;
	bool byte1 :1;
	bool byte2 :1;
	bool byte3 :1;
	bool byte4 :1;
	bool byte5 :1;
	bool byte6 :1;
	bool byte7 :1;
} __attribute__((packed)) byteBitmap_t;

typedef struct specialBlockGroup_t{
	superBlock_t superBlock;
	groupDescriptor_t* groupDescriptorTable;
	byteBitmap_t* blockBitmap; //cada bit representa si el bloque dentro del grupo esta usado (1) o libre (0).
	byteBitmap_t* inodeBitmap; //cada bit representa si el inodo correspondiente en la tabla de inodos esta usado (1) o libre (0). Los reservados son marcados como usados.
	inodeStructure_t* inodeTable;
	uint8_t* dataBlock;
} /*__attribute__((packed))*/ specialBlockGroup_t;

typedef struct blockGroup_t{
	byteBitmap_t* blockBitmap; //cada bit representa si el bloque dentro del grupo esta usado (1) o libre (0).
	byteBitmap_t* inodeBitmap; //cada bit representa si el inodo correspondiente en la tabla de inodos esta usado (1) o libre (0). Los reservados son marcados como usados.
	inodeStructure_t* inodeTable;
	uint8_t* dataBlock;
} /*__attribute__((packed))*/ blockGroup_t;

typedef struct directoryEntry_t{
	uint32_t inode; //numero que indica el inodo del archivo, si es 0 la entrada no esta siendo usada.
	uint16_t recLen; //desplazamiento hasta la proxima entrada de directorio desde el comienzo de la actual.
	uint8_t nameLen; //cantidad de caracteres del nombre.
	uint8_t fileType;
	char* name;
} /*__attribute__((packed))*/ directoryEntry_t;

typedef struct nodoBloque_t{
	char* contenidoBloque;
	struct nodoBloque_t* sig;
} /*__attribute__((packed))*/ nodoBloque_t;

typedef struct attrDirArch_t{
	mode_t modo;
	size_t size;
} /*__attribute__((packed))*/ attrDirArch_t;

//FUNCIONES
//LECTURA Y ESCRITURA DE BLOQUES
char* leerBloqueLocal(uint64_t, uint64_t);

char* leerBloqueGlobal(uint64_t);

char* leerParteBloqueLocal(uint64_t, uint64_t, uint64_t, uint64_t);

char* leerParteBloqueGlobal(uint64_t, uint64_t, uint64_t);

uint8_t escribirBloqueLocal(uint64_t, uint64_t, char*);

uint8_t escribirBloqueGlobal(uint64_t, char*);

uint8_t escribirParteBloqueLocal(uint64_t, uint64_t, uint64_t, uint64_t, char*);

uint8_t escribirParteBloqueGlobal(uint64_t, uint64_t, uint64_t, char*);

uint64_t deBloqueLocalAGlobal(uint64_t, uint64_t, uint64_t);

uint64_t deBloqueGlobalALocal(uint64_t, uint64_t);

//LECTURA DE ESTRUCTURAS EN EL DISCO

superBlock_t leerSuperBlock(void);

uint16_t cantBlockGroups(void);

uint64_t groupDescriptorTableSize(void);

uint8_t bloqueInicioGroupDescriptorTable(void);

uint16_t cantBloquesGroupDescriptorTable(void);

groupDescriptor_t* leerGroupDescriptorTable(void);

void cargarStaticGroupDescriptorTable(groupDescriptor_t*);

uint64_t blockBitmapSize(void);

uint8_t estaOcupadoBloque(byteBitmap_t*, uint64_t);

uint64_t inodeBitmapSize(void);

uint8_t estaOcupadoInodo(byteBitmap_t*, uint64_t);

uint64_t inodeTableSize();

inodeStructure_t* parsearInodeTable(nodoBloque_t*, nodoBloque_t*);

void encolarBloque(nodoBloque_t**, nodoBloque_t**, char* );

char* desencolarBloque(nodoBloque_t**, nodoBloque_t**);

uint64_t cantidadNodosBloques(nodoBloque_t*, nodoBloque_t*);

uint8_t buscarEnDirBloque(char* bloque, uint64_t cantBytes, char* nombre, inodeStructure_t* inodoBuscado);

uint8_t buscarEnDirNivel0(uint32_t* bloques, uint64_t cantPunteros, char* nombre, inodeStructure_t* inodoBuscado);

uint8_t buscarEnDirNivel1(uint32_t* bloques, uint64_t cantPunteros, char* nombre, inodeStructure_t* inodoBuscado);

uint8_t buscarEnDirNivel2(uint32_t* bloques, uint64_t cantPunteros, char* nombre, inodeStructure_t* inodoBuscado);

uint8_t buscarEnDirNivel2(uint32_t* bloques, uint64_t cantPunteros, char* nombre, inodeStructure_t* inodoBuscado);

uint8_t buscarEnDir(inodeStructure_t, char*, inodeStructure_t*);

inodeStructure_t inodoDirectorioRaiz(void);

uint8_t obtenerInodoPath(char*, inodeStructure_t*);

int32_t crearArchivo(char*, mode_t);

int32_t leerDirectorio(char*, off_t);

int32_t obtenerAtributos(char*, attrDirArch_t*);

char* leerGrupoDeBloques(uint64_t , uint32_t , uint32_t ,  FILE*  );

uint8_t esPotencia(uint64_t, uint8_t);
int64_t buscarInodoLibre(byteBitmap_t *,uint32_t );
int64_t buscarBloqueLibre(byteBitmap_t*,uint32_t);

void finalizarExtended2(void);

#endif /* LIBEXTENDED2_H_ */
